#pragma once
/*
Backup File System Core
*/
#include <Windows.h>
#include <string>
#include <mutex>
#include <map>
#include <vector>
#include <memory>
#include <unordered_map>

#include "../db/BackupFSDB.h"
#include "BackupFSDefines.h"
#include "BackupFSBitmap.h"

/*
Data file operation
This class is responsible for the reading and writing operations of data files, 
and is responsible for the application and release of file blocks, etc.
*/
namespace BackupFS
{

	class BackupFSCore
	{
	public:
		static BackupFSCore* GetInstance()
		{
			std::lock_guard<std::mutex> locker(_Locker);
			if (_Instance == nullptr) {
				_Instance = new BackupFSCore();
			}
			return _Instance;
		}
	protected:
		BackupFSCore();
		virtual ~BackupFSCore();
	public:
		static std::atomic<LONGLONG> FsInodeNumber;
		static std::atomic<LONGLONG> DataBlockId;

		bool Init(const std::wstring& data_path, LONGLONG fs_size,bool &has_db);
		LONGLONG GetFsSize() { return _FsSize; }
		LONGLONG GetUsedSize() { return _UsedSize; }
		LONGLONG GetFreeSize();
		void SetFsSize(LONGLONG size);
		LONGLONG AddUsedSize(LONGLONG used_size);
		LONGLONG Read(LPVOID buffer, LONGLONG bufferlength, LONGLONG offset);
		LONGLONG ReadNormal(LPVOID buffer, LONGLONG bufferlength, LONGLONG offset);
		LONGLONG ReadForIncremental(LPVOID buffer, LONGLONG bufferlength, LONGLONG offset);

		LONGLONG Write(LPCVOID buffer, LONGLONG number_of_bytes_to_write, LONGLONG offset);
		LONGLONG WriteNormal(LPCVOID buffer, LONGLONG number_of_bytes_to_write, LONGLONG offset);
		LONGLONG WriteForIncremental(LPCVOID buffer, LONGLONG number_of_bytes_to_write, LONGLONG offset);
		void* GetDb() { return _FsDb.GetDb(); }
		void GetStartTime(LONGLONG& start_time, LONGLONG& start_tickcount);
		std::shared_ptr<DATA_BLOCK> GetNewDataBlock(LONGLONG offset,LONGLONG length);
		void StopFS();
		void RemoveFileBlocks(const std::list<std::shared_ptr<DATA_BLOCK>>& blocks);
		void SetReadOnly(bool read_only) { _ReadOnly = read_only; }
		bool IsReadOnlyFS() { return _ReadOnly; }
		void SetMode(FILE_SYSTEM_MODE mode) { _Mode = mode; }
	private:
		bool _OpenCoreFiles();
		bool _SetSparseRange(HANDLE hFile, LONGLONG fileOffset, LONGLONG length);
		bool _UpdateIncrementalBitmap(LONGLONG offset, LONGLONG length);
		std::wstring _GetExtName(FILE_SYSTEM_MODE mode);
	private:
		std::atomic<LONGLONG> _CurrentDataFileOffset = 0;
		std::wstring _DataPath;
		std::wstring _DataFile;
		std::wstring _BaseDataFile;
		std::wstring _DbFile;
		std::wstring _FlagFile;
		std::wstring _BitmapFile;
		std::atomic<LONGLONG> _FsSize = MAXLONGLONG;
		std::atomic <LONGLONG> _UsedSize = 0;
		// handles
		HANDLE _HandleDataFile = INVALID_HANDLE_VALUE;
		HANDLE _HandleBaseDataFile = INVALID_HANDLE_VALUE;
		HANDLE _HandleFlag = INVALID_HANDLE_VALUE;
		HANDLE _HandleBitmap = INVALID_HANDLE_VALUE;
		static std::mutex _Locker;
		static BackupFSCore* _Instance;
		BackupFSDB _FsDb;
		FILE_HEADER _FileHeader = { 0 };
		bool _ReadOnly = false;
		//for file time attributes
		LONGLONG _StartTime;
		LONGLONG _StartTickCount;
		FILE_SYSTEM_MODE _Mode = FILE_SYSTEM_MODE::NORMAL_MODE;
		std::unordered_map<LONGLONG, std::shared_ptr<BackupFSBitmap>> _IncrementalBitmap;
		LONGLONG _BaseFileSize = 0;
	};
}
